package simpleGeom;

public class MTrianglePreCalcOption {

	
	//----------------------------------------------------------------------------
	
	Vec3D v1;
	Vec3D v0;
	Vec3D v2;
	 Vec3D edge0,edge1;
	 double a00,a01,a11,det;
	 
	 float nx,ny,nz,d0;
	
	public MTrianglePreCalcOption(float x1,float y1,float z1,float x2,float y2,float z2,float x3,float y3,float z3) {
		v0=new Vec3D(x1,y1,z1);
		v1 = new Vec3D(x2, y2, z2);
		v2 = new Vec3D(x3, y3, z3);
		edge0 = Vec3D.sub(v1, v0);
		edge1 = Vec3D.sub(v2, v0);
		a00 = edge0.magSqr();
		a01 = edge0.dot(edge1);
		a11 = edge1.magSqr();
		det = Math.abs(a00 * a11 - a01 * a01);

		float ux = x2 - x1;
		float uy = y2 - y1;
		float uz = z2 - z1;
		float vx = x3 - x1;
		float vy = y3 - y1;
		float vz = z3 - z1;
		nx = uy * vz - uz * vy;
		ny = uz * vx - ux * vz;
		nz = ux * vy - uy * vx;
		float mag = getLength(nx, ny, nz);
		nx /= mag;
		ny /= mag;
		nz /= mag;
		d0 = -dot(nx, ny, nz, x1, y1, z1);

	}
	
	public float getLength(float vx,float vy,float vz){
		return (float)Math.sqrt(vx*vx+vy*vy+vz*vz);
	}
	double getDistance(float px,float py,float pz){
		return Math.sqrt(getDistanceSqr(px,py,pz));
	}
	
	double getDistanceSqr(float px,float py,float pz)
	{
	  //http://www.geometrictools.com/LibMathematics/Distance/DistanceBody.html
		Vec3D diff=new Vec3D(v0.x-px,v0.y-py,v0.z-pz);
	    double b0 = diff.dot(edge0);
	    double b1 = diff.dot(edge1);
	    double c = diff.magSqr();
	    double s = a01*b1 - a11*b0;
	    double t = a01*b0 - a00*b1;
	    double sqrDistance;
	   
	    if (s + t <= det)
	    {
	        if (s < (double)0)
	        {
	            if (t < (double)0)  // region 4
	            {
	                if (b0 < (double)0)
	                {
	                    t = (double)0;
	                    if (-b0 >= a00)
	                    {
	                        s = (double)1;
	                        sqrDistance = a00 + ((double)2)*b0 + c;
	                    }
	                    else
	                    {
	                        s = -b0/a00;
	                        sqrDistance = b0*s + c;
	                    }
	                }
	                else
	                {
	                    s = (double)0;
	                    if (b1 >= (double)0)
	                    {
	                        t = (double)0;
	                        sqrDistance = c;
	                    }
	                    else if (-b1 >= a11)
	                    {
	                        t = (double)1;
	                        sqrDistance = a11 + ((double)2)*b1 + c;
	                    }
	                    else
	                    {
	                        t = -b1/a11;
	                        sqrDistance = b1*t + c;
	                    }
	                }
	            }
	            else  // region 3
	            {
	                s = (double)0;
	                if (b1 >= (double)0)
	                {
	                    t = (double)0;
	                    sqrDistance = c;
	                }
	                else if (-b1 >= a11)
	                {
	                    t = (double)1;
	                    sqrDistance = a11 + ((double)2)*b1 + c;
	                }
	                else
	                {
	                    t = -b1/a11;
	                    sqrDistance = b1*t + c;
	                }
	            }
	        }
	        else if (t < (double)0)  // region 5
	        {
	            t = (double)0;
	            if (b0 >= (double)0)
	            {
	                s = (double)0;
	                sqrDistance = c;
	            }
	            else if (-b0 >= a00)
	            {
	                s = (double)1;
	                sqrDistance = a00 + ((double)2)*b0 + c;
	            }
	            else
	            {
	                s = -b0/a00;
	                sqrDistance = b0*s + c;
	            }
	        }
	        else  // region 0
	        {
	            // minimum at interior point
	            double invDet = ((double)1)/det;
	            s *= invDet;
	            t *= invDet;
	            sqrDistance = s*(a00*s + a01*t + ((double)2)*b0) +
	                t*(a01*s + a11*t + ((double)2)*b1) + c;
	        }
	    }
	    else
	    {
	        double tmp0, tmp1, numer, denom;

	        if (s < (double)0)  // region 2
	        {
	            tmp0 = a01 + b0;
	            tmp1 = a11 + b1;
	            if (tmp1 > tmp0)
	            {
	                numer = tmp1 - tmp0;
	                denom = a00 - ((double)2)*a01 + a11;
	                if (numer >= denom)
	                {
	                    s = (double)1;
	                    t = (double)0;
	                    sqrDistance = a00 + ((double)2)*b0 + c;
	                }
	                else
	                {
	                    s = numer/denom;
	                    t = (double)1 - s;
	                    sqrDistance = s*(a00*s + a01*t + ((double)2)*b0) +
	                        t*(a01*s + a11*t + ((double)2)*b1) + c;
	                }
	            }
	            else
	            {
	                s = (double)0;
	                if (tmp1 <= (double)0)
	                {
	                    t = (double)1;
	                    sqrDistance = a11 + ((double)2)*b1 + c;
	                }
	                else if (b1 >= (double)0)
	                {
	                    t = (double)0;
	                    sqrDistance = c;
	                }
	                else
	                {
	                    t = -b1/a11;
	                    sqrDistance = b1*t + c;
	                }
	            }
	        }
	        else if (t < (double)0)  // region 6
	        {
	            tmp0 = a01 + b1;
	            tmp1 = a00 + b0;
	            if (tmp1 > tmp0)
	            {
	                numer = tmp1 - tmp0;
	                denom = a00 - ((double)2)*a01 + a11;
	                if (numer >= denom)
	                {
	                    t = (double)1;
	                    s = (double)0;
	                    sqrDistance = a11 + ((double)2)*b1 + c;
	                }
	                else
	                {
	                    t = numer/denom;
	                    s = (double)1 - t;
	                    sqrDistance = s*(a00*s + a01*t + ((double)2)*b0) +
	                        t*(a01*s + a11*t + ((double)2)*b1) + c;
	                }
	            }
	            else
	            {
	                t = (double)0;
	                if (tmp1 <= (double)0)
	                {
	                    s = (double)1;
	                    sqrDistance = a00 + ((double)2)*b0 + c;
	                }
	                else if (b0 >= (double)0)
	                {
	                    s = (double)0;
	                    sqrDistance = c;
	                }
	                else
	                {
	                    s = -b0/a00;
	                    sqrDistance = b0*s + c;
	                }
	            }
	        }
	        else  // region 1
	        {
	            numer = a11 + b1 - a01 - b0;
	            if (numer <= (double)0)
	            {
	                s = (double)0;
	                t = (double)1;
	                sqrDistance = a11 + ((double)2)*b1 + c;
	            }
	            else
	            {
	                denom = a00 - ((double)2)*a01 + a11;
	                if (numer >= denom)
	                {
	                    s = (double)1;
	                    t = (double)0;
	                    sqrDistance = a00 + ((double)2)*b0 + c;
	                }
	                else
	                {
	                    s = numer/denom;
	                    t = (double)1 - s;
	                    sqrDistance = s*(a00*s + a01*t + ((double)2)*b0) +
	                        t*(a01*s + a11*t + ((double)2)*b1) + c;
	                }
	            }
	        }
	    }

	    // Account for numerical round-off error.
	    if (sqrDistance < (double)0)
	    {
	        sqrDistance = (double)0;
	    }

	   // mClosestPoint0 = mPoint;
	  //  mClosestPoint1 = mTriangle->v0 + s*edge0 + t*edge1;
	  //  mTriangleBary[1] = s;
	  //  mTriangleBary[2] = t;
	  //  mTriangleBary[0] = (double)1 - s - t;
	    return sqrDistance;
	}
	
	
	public static float dot(float x1,float y1,float z1,float x2,float y2,float z2){
		return x1 * x2 + y1 * y2 + z1 * z2;
	}
	public float getDistancePlane(float x, float y, float z){
		return d0+dot(nx,ny,nz,x,y,z);
		
	}
	
	public void calculateBounds(float[] bounds){
		bounds[0] = v0.x;
		bounds[1] = v0.y;
		bounds[2] =  v0.z;
		bounds[3] =  v0.x;
		bounds[4] = v0.y;
		bounds[5] =  v0.z;
		
		bounds[0]=Math.min(bounds[0],v1.x);
		bounds[0]=Math.min(bounds[0],v2.x);
		bounds[1]=Math.min(bounds[1],v1.y);
		bounds[1]=Math.min(bounds[1],v2.y);
		bounds[2]=Math.min(bounds[2],v1.z);
		bounds[2]=Math.min(bounds[2],v2.z);
		
		bounds[3]=Math.max(bounds[3],v1.x);
		bounds[3]=Math.max(bounds[3],v2.x);
		bounds[4]=Math.max(bounds[4],v1.y);
		bounds[4]=Math.max(bounds[4],v2.y);
		bounds[5]=Math.max(bounds[5],v1.z);
		bounds[5]=Math.max(bounds[5],v2.z);
	}
}
